﻿using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using FSquirrel.Design;
using FSquirrel.Model;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Threading;
using System.Threading.Tasks;
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections;
using FSquirrel.Helpers;
using FSquirrel.Messages;
using System.IO;
using FileSquirrel.Logic;
using FileSquirrel.Logic.XSD;
using FSquirrel.Properties;
using System.Diagnostics;

namespace FSquirrel.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        /// <summary>
        /// Initializes a new instance of the ShowListViewModel class.
        /// </summary>
        public MainViewModel()
        {

            LoadLibrary();
            SelectedTreeviewCommand = new RelayCommand<object>(SelectedTreeviewChanged);
            CheckAllCommand = new RelayCommand<object>(ChangeFilteredChekcAll);
            SpacebarDataGridCommand = new RelayCommand<object>(CheckboxFilterItemChange);
            RequestCommand = new RelayCommand<string>(RequestProcess);
            FileDropCommand = new RelayCommand<DragEventArgs>(FileDropProcess);
            ResetLibraryCommand = new RelayCommand(ResetLibrary);
            LoadExternalFileCommand = new RelayCommand<string>(LoadExternalFile);
            TreeRequestCommand = new RelayCommand(TreeRequestProcess);
            RefreshLibraryCommand = new RelayCommand<string>(RefreshProcess);
            OpenLocationCommand = new RelayCommand<object>(OpenLocationProcess);


            libupprogress.ProgressChanged += libupprogress_ProgressChanged;

        }

        #region Lib Update Progress

        void libupprogress_ProgressChanged(object sender, LibraryUpdateEventArguments e)
        {
            LibUpdateIndex = e.Index;
            LibUpdateCatName = e.CatName;
            LibUpdateCount = e.Count;

            RaisePropertyChanged("LibUpdateIndex");
            RaisePropertyChanged("LibUpdateCatName");
            RaisePropertyChanged("LibUpdateCount");

        }

        public int LibUpdateIndex { get; private set; }
        public int LibUpdateCount { get; private set; }
        public string LibUpdateCatName { get; private set; }

        #endregion

        #region Properties

        //RelayCommands
        public RelayCommand<object> SelectedTreeviewCommand { get; private set; }
        public RelayCommand<object> CheckAllCommand { get; private set; }
        public RelayCommand<object> SpacebarDataGridCommand { get; private set; }
        public RelayCommand<string> RequestCommand { get; private set; }
        public RelayCommand<DragEventArgs> FileDropCommand { get; private set; }
        public RelayCommand ResetLibraryCommand { get; private set; }
        public RelayCommand<string> LoadExternalFileCommand { get; private set; }
        public RelayCommand TreeRequestCommand { get; private set; }
        public RelayCommand<string> RefreshLibraryCommand { get; private set; }
        public RelayCommand<object> OpenLocationCommand { get; private set; }


        Progress<LibraryUpdateEventArguments> libupprogress = new Progress<LibraryUpdateEventArguments>();

        //Properties
        private ObservableCollection<FileRowModel> _library = new ObservableCollection<FileRowModel>();
        private ObservableCollection<FileRowModel> _filtershowlistcollection = new ObservableCollection<FileRowModel>();
        private string _filtertext = string.Empty;
        private bool _allcheckselection = false;
        private ListCollectionView _showlistcollection;
        private string _librarytitle = Settings.Default.LibraryName;


        public const string ShowListCollectionPropertyName = "ShowListCollection";
        public const string AllCheckSelectionPropertyName = "AllCheckSelection";
        public const string FilterShowListCollectionPropertyName = "FilterShowListCollection";
        public const string CategoriesPropertyName = "Categories";
        public const string TotalSizePropertyName = "TotalSize";
        public const string FilterTextPropertyName = "FilterText";
        public const string LibraryTilePropertyName = "LibraryTile";
        public const string IsBusyRefreshPropertyName = "IsBusyRefresh";





        public const string ShowSelectedItemPropertyName = "ShowSelectedItem";

        private FileRowModel _showselecteditem = null;

        public FileRowModel ShowSelectedItem
        {
            get
            {
                return _showselecteditem;
            }

            set
            {
                if (_showselecteditem == value)
                {
                    return;
                }

                RaisePropertyChanging(ShowSelectedItemPropertyName);
                _showselecteditem = value;
                RaisePropertyChanged(ShowSelectedItemPropertyName);
            }
        }

        public string LibraryTile
        {
            get
            {
                return _librarytitle;
            }

            set
            {
                if (_librarytitle == value)
                {
                    return;
                }

                RaisePropertyChanging(LibraryTilePropertyName);
                _librarytitle = value;
                RaisePropertyChanged(LibraryTilePropertyName);
            }
        }

        public ListCollectionView ShowListCollection
        {
            get
            {
                if (_showlistcollection != null && _showlistcollection.SortDescriptions.Count == 0)
                {
                    _showlistcollection.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
                    _showlistcollection.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
                    _showlistcollection.SortDescriptions.Add(new SortDescription("ShowName", ListSortDirection.Ascending));
                    _showlistcollection.SortDescriptions.Add(new SortDescription("ShowSeason", ListSortDirection.Ascending));
                }

                return _showlistcollection;
            }

            set
            {
                if (_showlistcollection == value)
                {
                    return;
                }

                RaisePropertyChanging(ShowListCollectionPropertyName);
                _showlistcollection = value;
                RaisePropertyChanged(ShowListCollectionPropertyName);
                RaisePropertyChanged(TotalSizePropertyName);

            }
        }

        public ObservableCollection<FileRowModel> FilterShowListCollection
        {
            get
            {

                return _filtershowlistcollection;

            }

            set
            {
                if (_filtershowlistcollection == value)
                {
                    return;
                }

                RaisePropertyChanging(FilterShowListCollectionPropertyName);
                _filtershowlistcollection = value;
                RaisePropertyChanged(FilterShowListCollectionPropertyName);

                RaisePropertyChanged(TotalSizePropertyName);
            }
        }



        private bool _isbusyrefresh = false;

        public bool IsBusyRefresh
        {
            get
            {
                return _isbusyrefresh;
            }

            set
            {
                if (_isbusyrefresh == value)
                {
                    return;
                }

                RaisePropertyChanging(IsBusyRefreshPropertyName);
                _isbusyrefresh = value;
                RaisePropertyChanged(IsBusyRefreshPropertyName);
                RaisePropertyChanged("IsBusyDisable");
            }
        }

        public bool IsBusyDisable
        {
            get
            {
                return !IsBusyRefresh;
            }

        }

        public bool AllCheckSelection
        {
            get
            {
                return _allcheckselection;
            }

            set
            {
                if (_allcheckselection == value)
                {
                    return;
                }

                RaisePropertyChanging(AllCheckSelectionPropertyName);
                _allcheckselection = value;
                RaisePropertyChanged(AllCheckSelectionPropertyName);
            }
        }

        public int TotalSize
        {
            get
            {

                if (ShowListCollection != null)
                {
                    return (from dr in ShowListCollection.Cast<FileRowModel>()
                            select dr.Size).Sum();
                }
                return 0;
            }
        }

        public string ListToolTip
        {
            get
            {

                if (ShowListCollection != null)
                {
                    FileSizeConverter fsc = new FileSizeConverter();

                    var _list = ShowListCollection.Cast<FileRowModel>().Where(x => x.IsSelected);
                    var _icount = _list.Count();
                    if (_icount > 0)
                    {
                        var iSize = (from dr in _list
                                     select dr.Size).Sum();

                        string _size = fsc.Convert(iSize, typeof(string), null, null).ToString();

                        return string.Format("Items selected: {0}  Total Size: {1}", _icount, _size);
                    }

                }
                return string.Empty;
                RaisePropertyChanged("ListToolTip");
            }
        }

        public string FilterText
        {
            get
            {
                return _filtertext;
            }

            set
            {

                //Clear selection of items if searched or treeview results are shown
                ShowListCollection.Cast<FileRowModel>().ToList().ForEach(x => x.IsSelected = false);

                //Clear checkbox header
                AllCheckSelection = false;

                if (_filtertext == value)
                {
                    return;
                }


                RaisePropertyChanging(FilterTextPropertyName);
                _filtertext = value;
                if (string.IsNullOrEmpty(_filtertext))
                {
                    ShowListCollection.Filter = null;

                }
                else
                {
                    ShowListCollection.Filter = new Predicate<object>(x => ((FileRowModel)x).Name.ToUpper().Contains(_filtertext.ToUpper()));

                }

                RaisePropertyChanged(FilterShowListCollectionPropertyName);
                RaisePropertyChanged(FilterTextPropertyName);
                RaisePropertyChanged(TotalSizePropertyName);
            }
        }


        #endregion Properties

        #region Events

        //Used to open library location and selected item in datagrid view
        private void OpenLocationProcess(object OLP)
        {

            if (OLP == null)
            {
                Process.Start("explorer.exe", string.Format("/select,{0}", Path.Combine(Settings.Default.LibraryDir, string.Format("{0}.{1}", Settings.Default.LibraryName, "fsl"))));

            }
            else
            {
                if (File.Exists(ShowSelectedItem.Path))
                {
                    Process.Start("explorer.exe", string.Format("/select,{0}", ShowSelectedItem.Path));
                }
            }
        }

        private void RefreshProcess(string refreshaction)
        {
            IsBusyRefresh = true;

            switch (refreshaction)
            {
                case "FULL":
                    var dr = MessageBox.Show("Rebuild Library?. This will take some time to complete", "Rebuild Library", MessageBoxButton.YesNo, MessageBoxImage.Question);
                    if (dr == MessageBoxResult.Yes)
                    {

                        FileInfo delibfile = new FileInfo(Path.Combine(Settings.Default.LibraryDir, string.Format("{0}.{1}", Settings.Default.LibraryName, "fsl")));
                        delibfile.Delete();
                        Reader.GlobalLibrary._Files.Clear();

                    }
                    break;
            }
            UpdateLibrary();


        }

        private void TreeRequestProcess()
        {
            RequestMessage RM = new RequestMessage();
            RM.RAction = RequestAction.Add;
            RM.requestlist = ShowListCollection.Cast<FileRowModel>().ToList<FileRowModel>();
            Messenger.Default.Send(RM);
        }


        private void LoadExternalFile(string fileaction)
        {

            var opd = new System.Windows.Forms.OpenFileDialog();

            if (fileaction.Equals("LIBRARY"))
            {
                opd.Filter = "FileSquirrel Library (*.fsl) | *.fsl";
                opd.Title = "FileSquirrel - Select Library File to open and compare against.";
                if (opd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    ProcessOutsideLibrary(opd.FileName);
                }
            }
            else if (fileaction.Equals("REQUEST"))
            {
                opd.Filter = "FileSquirrel Request(*.fsr) | *.fsr";
                opd.Title = "FileSquirrel - Select Request File to process";
                if (opd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    ProcessIncommingRequest(opd.FileName);
                }
            }




        }



        private void ResetLibrary()
        {
            Reader.ResetToOwnLibrary();
            LoadLibrary();
            LibraryTile = Settings.Default.LibraryName;
        }


        private void FileDropProcess(DragEventArgs EventArgs)
        {
            string[] droppedFilenames = EventArgs.Data.GetData(DataFormats.FileDrop, true) as string[];

            if (droppedFilenames.Count() > 0)
            {
                switch (Path.GetExtension(droppedFilenames[0]).ToUpper())
                {
                    case ".FSR":
                        ProcessIncommingRequest(droppedFilenames[0]);
                        break;

                    case ".FSL":
                        ProcessOutsideLibrary(droppedFilenames[0]);
                        break;

                    default:
                        break;
                }
            }
        }





        private void RequestProcess(string strAction)
        {

            if (strAction.Equals("Clear"))
            {
                RequestMessage RM = new RequestMessage();
                RM.RAction = RequestAction.Clear;

                Messenger.Default.Send(RM);

            }
            else if (strAction.Equals("Add"))
            {

                RequestMessage RM = new RequestMessage();
                RM.RAction = RequestAction.Add;
                RM.requestlist = ShowListCollection.Cast<FileRowModel>().Where(x => x.IsSelected).ToList<FileRowModel>();
                Messenger.Default.Send(RM);


            }
        }


        private void CheckboxFilterItemChange(object sender)
        {
            IList items = (IList)sender;
            var collection = items.Cast<FileRowModel>();

            //If any current are select and more than to be selected then change all to true
            int _countselected = collection.Count(x => x.IsSelected);

            bool _partialselect = items.Count > _countselected;


            foreach (FileRowModel item in collection)
            {
                if (_partialselect)
                {
                    item.IsSelected = true;
                }
                else
                {
                    item.IsSelected = !item.IsSelected;
                }
            }
        }


        private void ChangeFilteredChekcAll(object sender)
        {
            if (sender.ToString().Equals("Clear"))
            {
                if (AllCheckSelection)
                {
                    AllCheckSelection = false;
                }

            }
            else
            {
                ShowListCollection.Cast<FileRowModel>().ToList().ForEach(x => x.IsSelected = Convert.ToBoolean(sender));

                //foreach (var item in FilterShowListCollection)
                //{
                //    item.IsSelected = Convert.ToBoolean(sender);
                //}
                RaisePropertyChanged(FilterShowListCollectionPropertyName);
                //ShowListCollection.Refresh();
            }
        }



        private void SelectedTreeviewChanged(object sender)
        {
            ObservableCollection<FileRowModel> RVMrequestlist = ViewModelLocator.RequestVM.RequestListCollection;

            ObservableCollection<FileRowModel> _tmp = new ObservableCollection<FileRowModel>();

            foreach (FileRowModel fileRowModel in GetAllFileRows((((CollectionViewGroup)(sender)))))
            {
                _tmp.Add(fileRowModel);
            }

            ShowListCollection.Filter = new Predicate<object>(x => _tmp.Contains(((FileRowModel)x)));

            FilterText = string.Empty;

            RaisePropertyChanged(TotalSizePropertyName);

            //ShowListCollection.Cast<FileRowModel>().Where(x => RVMrequestlist.Any(y => x.Name == y.Name)).ToList().ForEach(z => z.IsSelected = true);


        }

        private ObservableCollection<FileRowModel> GetAllFileRows(CollectionViewGroup collitems)
        {
            ObservableCollection<FileRowModel> _tmp = new ObservableCollection<FileRowModel>();

            foreach (var collitem in collitems.Items)
            {
                if (collitems.IsBottomLevel)
                {
                    _tmp.Add((FileRowModel)collitem);
                }
                else
                {
                    foreach (FileRowModel row in GetAllFileRows((CollectionViewGroup)collitem))
                    {
                        _tmp.Add(row);
                    }
                }
            }
            return _tmp;
        }

        #endregion Events


        #region Methods

        private async void LoadLibrary()
        {
            ShowListModel showmodel = new ShowListModel();

            var st = Task<ObservableCollection<FileRowModel>>.Factory.StartNew(() => showmodel.LibShows);
            await st;

            FilterShowListCollection = st.Result;

            ShowListCollection = CollectionViewSource.GetDefaultView(FilterShowListCollection) as ListCollectionView;
        }

        private async void UpdateLibrary()
        {
            FileSquirrel.Logic.XSD.UserSettings _userSettings = Reader.UserSettings;
            var st = Task.Factory.StartNew(() => _Indexer.GatherFiles(_userSettings.Category, libupprogress));
            await st;
            IsBusyRefresh = false;
            LoadLibrary();
        }

        private void ProcessIncommingRequest(string requestfilename)
        {
            ViewModelLocator.CopierVM.CopierVisibility = Visibility.Visible;
            ViewModelLocator.CopierVM.RequestFileName = requestfilename;
        }

        private void ProcessOutsideLibrary(string outsidelibraryname)
        {

            Reader.ResetToOwnLibrary();
            LibraryDataSet.FilesDataTable dinstinctFiles = Reader.GetDistinctFilesDataSet(Reader.GlobalLibrary._Files, outsidelibraryname);
            ViewModelLocator.RequestVM._Indexer.RequestFilesName = string.Format("{0}_RequestFrom_{1}",
                                                      Path.GetFileNameWithoutExtension(new FileInfo(outsidelibraryname).Name),
                                                      Settings.Default.LibraryName);
            LibraryTile = Path.GetFileNameWithoutExtension(new FileInfo(outsidelibraryname).Name);
            LoadLibrary();
        }

        #endregion

        private Indexer indexer;
        public Indexer _Indexer
        {
            get { return indexer ?? (indexer = new Indexer(Settings.Default.LibraryName, Settings.Default.LibraryDir)); }
        }
    }
}